梦入琼楼寒有月,行过石树冻无烟

pinia 基础

pinia overview

Pinia 是一个适用于 Vue2~3 的跨组件共享状态维持项目,与 vuex、bus 等原理类似,但都比前者简单高效许多,在 2019 年 11 年重新被设计使用,其维护团队为 Vuejs。

特点在于更加容易调试,可以使得 store 出现在其他组件中并使用,以及在不重新加载页面的情况下修改 store 共享数据,并保持现有状态,同时占用空间小的特点。

1
反观 Vuex 和专注于兄弟组件之间通信的 Bus 相比,Pinia 根据简单和[官方](https://github.com/vuejs/pinia)团队维护等特点深受开发人员喜爱。

Store

首先,Pinia 拥有和 Vuex 类似的特性及功能(毕竟是同类型项目),而 Store 的定义主要是可以让该数据被所有组件共享。

在本文中,我们主要通过 vue-cli 来构建 vue3 project,并使用 vue add vue-cli-plugin-pinia 来添加 pinia 支持。

之后可以在 src/store/ 下看到其自动帮我们所创建的 pinia store,之后我们可以重命名或者直接在此基础上进行开发,来进行共享数据。

同时他也会在 mian.js 文件下为我们引入 pinia 并使用,返回给 Vue。

在使用的时候,你需要记得,在 store 目录下的共享数据内的方里,默认的会为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { defineStore } from 'pinia'  

export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
double: state => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
})

我们需要记得导出的方法,也就是 useCounterStore 之后在组件中直接 import { useCounterStore } from "@/stores/index" 这么引用,然后在 setup() 语法糖下赋值给 store

1
2
3
4
5
6
7
  setup() {  
const store = useCounterStore()
return {
store,
}
},
})

这之后在 template 下,就可以通过插值 {{ store.count }} 来直接进行使用了。

1
这在官方文档关于定义 Store 中有详细的描述:“并且它需要一个唯一的名称,作为第一个参数传递”

State

StateStores 所定义的中心部分,也就是共享数据\状态的起点,在 PInia 中会被定义为返回初始的状态函数:

1
2
3
4
5
6
7
8
9
import { defineStore } from 'pinia'  

export const useTabStore = defineStore('tab', {
state: () => ({
/*
return {Array}
*/
rowItems: []
})

Getters & Actions

Actions

在此之前,我们需要知道,getters 是被动获取,也就是说需要有组件取调用这个方法。而 Actions 则是可以实现在文章开头,Pinia 所说的特性之一:”Stores appear in components where they are used”,即可以在组件中实现将组件的数据,传入到 State 中。

1
需要注意的是,在一般情况下,Vuex、和 Bus 很难去解决组件和组件之间的传值,需要通过 emit,props 等方法,先将兄弟组件的数据传给父组件,父组件再将数据传给兄弟组件,以此来实现传值。

在组件传值之前,我们首先需要在 store 下定义参数,准备接受组件所传来的数据,并之后传给 state() 下的共享状态变量 rowItems:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { defineStore } from 'pinia'  

export const useTabStore = defineStore('tab', {
state: () => ({
/*
return {Array} */ rowItems: []
}),
actions: {
addItem(name) {
this.rowItems.push(name)
},
},
})
1
在真实的开发环境中,一般先定义 ```state``` 下的共享变量,再去定义 ```actions```,之后才是 ```getters```

上述 Code 中,我们主要通过 this.rowItems.push 方法,来将获取到的 name 参数传递给 state,之后 getters 来获取 state 下的共享数据/状态变量。

下面,我们需要通过在传递数据的组件内,引入 import { useTabStore } from "@/stores";,之后按照 setup() 语法糖:

1
2
3
4
5
6
7
8
export default defineComponent({  
setup (props, {emit}) {
const tab = useTabStore()
return {
tab
}
},
})

由于我们是按照 setup() 语法糖的 Vue3 的写法,那么基本上数据是在 setup() 下的 return 来进行编写,我们需要做的就是通过 tab.addItem(value) 将数据传递给 stores,之后就完成了组件的传递。

Getters

可以理解为获得数据,他与 ```state``` 所定义的数据/状态是完全等价的,且处于被动,也就是说可以通过组件访问 ```getters``` 所关联的 ```state``` :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

```js
import { defineStore } from 'pinia'

export const useTabStore = defineStore('tab', {
state: () => ({
/*
return {Array} */ rowItems: []
}),
getters: {
items: (state) =>
state.rowItems.reduce((items, item) => {
console.log({name: item},'{name: item}')
items.push({name: item})
return items
}, []),
},
actions: {
addItem(name) {
this.rowItems.push(name)
console.log(name,'->>>>>>YES')
},
},
})

在上述的 Code 中,我们首先在 state 先定义共享状态 rowItems 变量,当获取数据的时候,我们需要他可以循环遍历,那么就通过 reduce之后 方法来按照数组的顺序来进行返回。

然后通过 push 方法将元素添加至数组的末尾,最后返回 items 变量,这是通过 actions 所获取到的数据并输出。

在数据的获取部分,我们需要在组件中同样引入 import { useTabStore } from "@/stores/index",然后按照 setup() 语法糖的写法:

1
2
3
4
5
6
7
8
export default defineComponent({  
setup (props, {emit}) {
const tab = useTabStore()
return {
tab
}
},
})

之后通过 template 的模板语法以及 v-forv-bind 就可以完成共享数据的循环输出:

1
2
3
<li v-for="item in store.items" :key="item.name">  
{{ item.name }}
</li>
⬅️ Go back